package l2ft.gameserver.instancemanager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;

import l2ft.gameserver.ai.FakePcs.ArcherFakePc;
import l2ft.gameserver.ai.FakePcs.FighterFakePc;
import l2ft.gameserver.ai.FakePcs.HealerFakePc;
import l2ft.gameserver.ai.FakePcs.MageFakePc;
import l2ft.gameserver.ai.FakePcs.TankFakePc;
import l2ft.gameserver.data.xml.holder.CharTemplateHolder;
import l2ft.gameserver.data.xml.holder.SkillAcquireHolder;
import l2ft.gameserver.model.Effect;
import l2ft.gameserver.model.SimpleSpawner;
import l2ft.gameserver.model.Skill;
import l2ft.gameserver.model.SkillLearn;
import l2ft.gameserver.model.entity.Reflection;
import l2ft.gameserver.model.instances.BufferInstance;
import l2ft.gameserver.model.instances.FakePcInstance;
import l2ft.gameserver.skills.effects.EffectTemplate;
import l2ft.gameserver.stats.Env;
import l2ft.gameserver.tables.SkillTable;
import l2ft.gameserver.templates.CharTemplate;
import l2ft.gameserver.templates.StatsSet;
import l2ft.gameserver.templates.npc.NpcTemplate;
import l2ft.gameserver.utils.Location;

public class FakePcFactory 
{
	private static final String[] names = {"Byun", "Dimaga", "blitz", "fermata", "zaraki", "Nestea", "Ritmix", "Squirtle", "laminal", "terious", "Curious", "Ryung", "sniper", "leenock", "Taeja", "Parting", "seed", "Yugioh", "virus", "Demuslim", "crank", "Losira", "tails", "Shine", "hyun", "forgg", "vines", "Denkan", "forsen", "meems", "Jethor", "turuk", "Bruzze", "Lunar", "Naugrim", "grokken", "Zion", "Snute", "zuth", "Nerchio", "serral", "Forsberg", "morrow", "kekmao", "hiflon", "fraer", "Lizalfo", "welmu", "Lazrar", "harstem", "Zanxala", "bellomo", "Jintetsu", "raest", "Freizy", "ejden", "Svetis", "Pluffs", "guilly", "mojagy", "bischu", "carnage", "Weiman", "Socke", "Select", "axslav", "Kihai", "Sheth", "zelniq", "Vibe", "Fenix", "cocoa", "Sarens", "seiplo", "Fuzer", "Seala", "predy", "nony", "inori", "Histyz", "Vayhy", "Bistein", "Gundam", "lengmo", "Tyloini", "revtine", "Xlous", "Commig", "uhenty", "Ganzi", "Trogger", "Jormson", "phaint", "Lucifron", "Paladog", "Bilek", "zroawai", "velidra", "Csours", "Luwak"};
	private static List<String> takenNames = new ArrayList<String>();
	public static final int[] mages = {94, 95, 103, 110, 115};
	public static final int bishop = 97;
	public static final int titan = 113;
	public static final int tyrant = 114;
	public static final int[] tanks = {90, 91, 99, 106};
	public static final int[] daggers = {93, 101, 108, 117};
	public static final int[] archers = {92, 102, 109};
	
	private static final int[] swordWeapons = {15830, 15871, 14120};
	private static final int[] daggerWeapons = {15834, 15875, 14127};
	private static final int[] doubleSwordWeapons = {15842, 15883, 14123};
	private static final int[] fistWeapons = {15846, 15887, 14130};
	private static final int[] mageWeapons = {15852, 15893, 14142};
	private static final int[] bowWeapons = {15859, 15903, 14149};
	private static final int[] shields = {15604, 15587, 13471};
	private static final int[] sigils = {15588 ,15605 ,12813};
	private static final int[][] robe = {{15577, 15580, 15574, 15583, 15586}, {15594, 15597, 15591, 15600, 15603}, {13434, 13444, 13139, 13445, 13446}};
	private static final int[][] light = {{15576, 15579, 15573, 15582, 15585}, {15593, 15596, 15590, 15599, 15602}, {13433, 13441, 13138, 13442, 13443}};
	private static final int[][] heavy = {{15575, 15578, 15572, 15581, 15584}, {15592, 15595, 15589, 15598, 15601}, {13432, 13438, 13137, 13439, 13440}};
	private static final int[] neck = {15719, 15722, 14164};
	private static final int[] ear = {15718, 15721, 14163};
	private static final int[] ring = {15717, 15720, 14165};
	
	private static final int[][] mageBuffs = {{1501,1},{1499,1},{1503,1},{1504,1},{1500,1},{1085,3},{1062,2},{1354,1},{1352,1},{1303,2},{1078,6},{1035,4},{1460,1},{1397,3},{1259,3},{1259,4},{1389,3},{1363,1},{1461,1},{1549,1},{273,1},{276,1},{365,1},{915,1},{989,1},{264,1},{267,1},{304,1},{349,1},{988,3},{529,1},{914,1},{1353,1},{1393,3},{1189,3}};
	private static final int[][] fighterBuffs = {{1085,3},{1500,1},{1352,1},{364,1},{988,3},{349,1},{304,1},{269,1},{267,1},{268,1},{264,1},{989,1},{275,1},{274,1},{271,1},{1549,1},{1519,1},{1461,1},{1363,1},{1388,3},{1542,1},{1259,4},{1035,4},{1062,2},{1502,1},{1504,1},{1501,1},{1503,1},{1499,1}};
	
	public static enum ArmorTypes
	{
		pd_head,
		pd_rhand,
		pd_lhand,
		pd_gloves,
		pd_chest,
		pd_legs,
		pd_feet
	}
	public static FakePcInstance newFakePc(int classId, boolean hero, Location loc, Reflection reflection)
	{
		return newFakePc(classId, hero, loc, reflection, -1);
	}
	
	public static FakePcInstance newFakePc(int classId, boolean hero, Location loc, Reflection reflection, int onlyRace)
	{
		int npcId = 50000;
		int templateId = 30754;
		String name;
		while(takenNames.contains(name = names[(int) Math.round(Math.random()*(names.length-1))]))
		{
			if(takenNames.size() >= names.length-5)
				takenNames.clear();
		}
		takenNames.add(name);
		String title = "";
		int clazz = classId;
		if(clazz == 0 || clazz == 1)
			clazz = mages[(int) Math.round(Math.random()*(mages.length-1))];
		StatsSet set = new StatsSet();
		set.set("npcId", npcId);
		set.set("displayId", templateId);
		set.set("name", name);
		set.set("title", title);

		set.set("aggroRange", "1000");
		set.set("ai_type", "MainFakePc");
		set.set("baseHpRate", 1);
		set.set("level", "85");
		set.set("rewardExp", "0");
		set.set("rewardRp", "0");
		set.set("rewardSp", "0");
		set.set("shots", "NONE");
		set.set("texture", "");
		set.set("type", "FakePc");

		CharTemplate template2 = CharTemplateHolder.getInstance().getTemplate(clazz, false);
		System.out.println("tempaklte for clazz:"+clazz+" :"+template2);
		for(Entry<String, Object> stats : template2.statsSet.entrySet())
			set.set(stats.getKey(), stats.getValue());
		set.set("basePAtk", set.getInteger("basePAtk")*3);
		set.set("basePDef", set.getInteger("basePDef")*2);
		set.set("baseMAtk", set.getInteger("baseMAtk")*3);
		set.set("baseMAtkSpd", set.getInteger("baseMAtkSpd")*3);
		set.set("saveSet", "true");
		set.putAll(getFakePcSet(clazz, name, hero, onlyRace));
		NpcTemplate template = new NpcTemplate(set);
		List<Skill> skills = new ArrayList<Skill>();
		for(int i = 0;i<50;i++)
		{

			Skill[] skillsArray = new Skill[skills.size()];
			for(int x = 0;x<skills.size();x++)
				skillsArray[x] = skills.get(x);
				
			Collection<SkillLearn> allSkills = SkillAcquireHolder.getInstance().getAllSkillsForClass(clazz, skillsArray, 85);
			for(SkillLearn skill : allSkills)
			{
				Skill skillInData = SkillTable.getInstance().getInfo(skill.getId(), skill.getLevel());
				skills.add(skillInData);
			}
		}
		for(Skill skill : skills)
			template.addSkill(skill);
		
		SimpleSpawner spawn = new SimpleSpawner(template);
		spawn.setLoc(loc);
		spawn.setAmount(1);
		spawn.setHeading(loc.h);
		spawn.setRespawnDelay(0);
		spawn.setReflection(reflection);
		FakePcInstance newNpc = (FakePcInstance)spawn.spawnOne();
		boolean mage = false;
		if(clazz == tyrant || clazz == titan)
			newNpc.setAI(new FighterFakePc(newNpc));
		if(clazz == bishop){
			mage = true;
			newNpc.setAI(new HealerFakePc(newNpc));
		}
		for(int i : daggers)
			if(clazz == i)
				newNpc.setAI(new FighterFakePc(newNpc));
		for(int i : tanks)
			if(clazz == i)
				newNpc.setAI(new TankFakePc(newNpc));
		for(int i : archers)
			if(clazz == i)
				newNpc.setAI(new ArcherFakePc(newNpc));
		for(int i : mages)
			if(clazz == i){
				mage = true;
				newNpc.setAI(new MageFakePc(newNpc));
			}
		if(mage)
			for(int[] data : mageBuffs)
				addEffect(newNpc, data);
		else
			for(int[] data : fighterBuffs)
				addEffect(newNpc, data);
		newNpc.setCurrentCp(newNpc.getMaxCp());
		newNpc.setCurrentHp(newNpc.getMaxHp(), false);
		newNpc.setCurrentMp(newNpc.getMaxMp());
		return newNpc;
	}
	
	private static void addEffect(FakePcInstance npc, int[] effectData)
	{
		Skill skill = SkillTable.getInstance().getInfo(effectData[0], effectData[1]);
		if(skill == null)
			return;
		
		BufferInstance.buffFakePc(npc, effectData[0], effectData[1]);
	}
	
	private static StatsSet getFakePcSet(int clazz, String name, boolean hero, int onlyRace)
	{
		StatsSet set = new StatsSet();
		set.put("sex", (int)Math.round(Math.random()));
		set.put("name", name);
		set.put("class", clazz);
		int race = onlyRace;
		if(race == -1)
			race = getRace(clazz);
		set.put("title", "");
		set.put("race", race);
		int grade = (int) Math.round(Math.random()*2);
		set.put("pd_head", getItems(clazz, ArmorTypes.pd_head, grade));
		set.put("pd_rhand", getItems(clazz, ArmorTypes.pd_rhand, grade));
		set.put("pd_lhand", getItems(clazz, ArmorTypes.pd_lhand, grade));
		set.put("pd_gloves", getItems(clazz, ArmorTypes.pd_gloves, grade));
		set.put("pd_chest", getItems(clazz, ArmorTypes.pd_chest, grade));
		set.put("pd_legs", getItems(clazz, ArmorTypes.pd_legs, grade));
		set.put("pd_feet", getItems(clazz, ArmorTypes.pd_feet, grade));
		set.put("lRing", ring[grade]);
		set.put("rRing", ring[grade]);
		set.put("lEarring", ear[grade]);
		set.put("rEarring", ear[grade]);
		set.put("necklace", neck[grade]);
		set.put("hair_style", 1);
		set.put("hair_color", 1);
		set.put("face", 1);
		set.put("hero", hero ? 1 : 0);
		set.put("pd_under", 1);
		set.put("pd_back", 1);
		set.put("hair_color", 1);
		set.put("enchant_effect", 0);
		set.put("pvp_flag", 0);
		set.put("karma", 0);
		set.put("invisible", 0);
		return set;
	}
	
	public static int getItems(int clazz, ArmorTypes part, int grade)
	{
		switch(part)
		{
			case pd_head:
				return getArmors(clazz)[grade][2];
			case pd_rhand:
				return getWeaponType(clazz)[grade];
			case pd_lhand:
				if(getShields(clazz) == null)
					return 0;
				return getShields(clazz)[grade];
			case pd_gloves:
				return getArmors(clazz)[grade][3];
			case pd_chest:
				return getArmors(clazz)[grade][0];
			case pd_legs:
				return getArmors(clazz)[grade][1];
			case pd_feet:
				return getArmors(clazz)[grade][4];
		}
		return 0;
	}

	private static int[] getWeaponType(int clazz)
	{
		for(int i : mages)
			if(clazz == i)
				return mageWeapons;
		for(int i : tanks)
			if(clazz == i)
				return swordWeapons;
		for(int i : daggers)
			if(clazz == i)
				return daggerWeapons;
		for(int i : archers)
			if(clazz == i)
				return bowWeapons;
		if(clazz == bishop)
			return mageWeapons;
		if(clazz == titan)
			return doubleSwordWeapons;
		if(clazz == tyrant)
			return fistWeapons;
		
		return bowWeapons;
	}
	
	private static int[] getShields(int clazz)
	{
		for(int i : mages)
			if(clazz == i)
				return sigils;
		for(int i : tanks)
			if(clazz == i)
				return shields;
		for(int i : daggers)
			if(clazz == i)
				return null;
		for(int i : archers)
			if(clazz == i)
				return bowWeapons;
		if(clazz == bishop)
			return sigils;
		if(clazz == titan)
			return doubleSwordWeapons;
		if(clazz == tyrant)
			return fistWeapons;
		return bowWeapons;
	}
	
	private static int[][] getArmors(int clazz)
	{
		for(int i : mages)
			if(clazz == i)
				return robe;
		for(int i : tanks)
			if(clazz == i)
				return heavy;
		for(int i : daggers)
			if(clazz == i)
				return light;
		for(int i : archers)
			if(clazz == i)
				return light;
		if(clazz == bishop)
			return robe;
		if(clazz == titan)
			return heavy;
		if(clazz == tyrant)
			return light;
		return light;
	}
	
	private static int getRace(int clazz)
	{
		if(clazz<=98)
			return 0;
		else if(clazz<=105)
			return 1;
		else if(clazz<=112)
			return 2;
		else if(clazz<=116)
			return 3;
		else if(clazz<=118)
			return 4;
		return 5;
	}
}